#ifndef _WX_PROPGRID_ODCOMBO_H_
#define _WX_PROPGRID_ODCOMBO_H_

#ifndef DOXYGEN
#include "wx/renderer.h"

#define wxODCCount  unsigned int
#define wxODCIndex  unsigned int

class wxTextCtrl;
class wxButton;

#define DLLIMPORT
#define WXDLLEXPORT_PGODC DLLIMPORT
#define wxODComboBoxNameStr _T("wxOwnerDrawnComboBox")

class WXDLLEXPORT_PGODC wxPGComboPopup;
class WXDLLEXPORT_PGODC wxPGComboControlBase;
class WXDLLEXPORT_PGODC wxPGOwnerDrawnComboBox;

enum {
  wxPGCC_DCLICK_CYCLES = 0x0100,
  wxPGCC_ALT_KEYS = 0x0200
};

#define wxPGCC_PROCESS_ENTER  0

enum {
  wxPGCC_BUTTON_OUTSIDE_BORDER = 0x0001,
  wxPGCC_POPUP_ON_MOUSE_UP = 0x0002,
  wxPGCC_NO_TEXT_AUTO_SELECT = 0x0004,
  wxPGCC_BUTTON_STAYS_DOWN = 0x0008,
  wxPGCC_FULL_BUTTON = 0x0010,
  wxPGCC_IFLAG_CREATED = 0x0100,
  wxPGCC_IFLAG_BUTTON_OUTSIDE = 0x0200,
  wxPGCC_IFLAG_INDENT_SET = 0x0400,
  wxPGCC_IFLAG_PARENT_TAB_TRAVERSAL = 0x0800,
  wxPGCC_IFLAG_HAS_NONSTANDARD_BUTTON = 0x1000
};


enum {
  wxPGCC_MF_ON_BUTTON = 0x0001,
};

struct wxPGComboControlFeatures {
  enum {
    MovableButton = 0x0001,
    BitmapButton = 0x0002,
    ButtonSpacing = 0x0004,
    TextIndent = 0x0008,
    PaintControl = 0x0010,
    PaintWritable = 0x0020,
    Borderless = 0x0040,
    All = MovableButton | BitmapButton |
          ButtonSpacing | TextIndent |
          PaintControl | PaintWritable |
          Borderless,
  };
};

class wxPGComboPopupWindow;

class WXDLLEXPORT_PGODC wxPGComboControlBase : public wxControl {
    friend class wxPGComboPopup;
    friend class wxPGComboPopupWindow;
  public:
    wxPGComboControlBase() : wxControl() { Init(); }

    bool Create( wxWindow *parent,
                 wxWindowID id,
                 const wxString& value,
                 const wxPoint& pos,
                 const wxSize& size,
                 long style,
                 const wxValidator& validator,
                 const wxString& name );

    virtual ~wxPGComboControlBase();

    virtual bool Destroy();
    virtual void ShowPopup();
    virtual void HidePopup();
    virtual void OnButtonClick();
    inline bool IsPopupShown() const { return m_isPopupShown; }
    void SetPopup( wxPGComboPopup* iface );
    wxPGComboPopup* GetPopup() const { return m_popupInterface; }
    wxWindow *GetPopupWindow() const { return m_winPopup; }
    wxWindow *GetPopupControl() const { return m_popup; }
    inline wxTextCtrl *GetTextCtrl() const { return m_text; }
    inline wxWindow *GetButton() const { return m_btn; }
    virtual bool Enable( bool enable = true );
    virtual bool Show( bool show = true );
    virtual bool SetFont( const wxFont& font );
    #if wxUSE_TOOLTIPS
    virtual void DoSetToolTip( wxToolTip *tip );
    #endif

    virtual wxString GetValue() const;
    virtual void SetValue( const wxString& value );
    void SetText( const wxString& value ) {
      SetValue( value );
    }
    virtual void Copy();
    virtual void Cut();
    virtual void Paste();
    virtual void SetInsertionPoint( long pos );
    virtual void SetInsertionPointEnd();
    virtual long GetInsertionPoint() const;
    virtual long GetLastPosition() const;
    virtual void Replace( long from, long to, const wxString& value );
    virtual void Remove( long from, long to );
    virtual void SetSelection( long from, long to );
    virtual void Undo();
    inline const wxRect& GetTextRect() const {
      return m_tcArea;
    }
    inline void SetPopupMinWidth( int width ) {
      m_widthMinPopup = width;
    }
    inline void SetPopupMaxHeight( int height ) {
      m_heightPopup = height;
    }
    inline void SetPopupExtents( int extLeft, int extRight ) {
      m_extLeft = extLeft;
      m_extRight = extRight;
    }
    void SetCustomPaintWidth( int width );
    inline int GetCustomPaintWidth() const { return m_widthCustomPaint; }
    void SetButtonPosition( int width = 0, int height = 0, int side = wxRIGHT,
                            int spacingX = 0 );
    void SetButtonBitmaps( const wxBitmap& bmpNormal,
                           bool blankButtonBg = false,
                           const wxBitmap& bmpPressed = wxNullBitmap,
                           const wxBitmap& bmpHover = wxNullBitmap,
                           const wxBitmap& bmpDisabled = wxNullBitmap );

    void SetTextIndent( int indent );
    inline wxCoord GetTextIndent() const {
      return m_absIndent;
    }
    virtual void DrawFocusBackground( wxDC& dc, const wxRect& rect, int flags );
    bool IsFocused() const {
      const wxWindow* curFocus = FindFocus();
      if( curFocus == this || ( m_text && curFocus == m_text ) ) {
        return true;
      }
      return false;
    }

    inline bool ShouldDrawFocus() const {
      const wxWindow* curFocus = FindFocus();
      return ( !m_isPopupShown &&
               ( curFocus == this || ( m_btn && curFocus == m_btn ) ) &&
               ( m_windowStyle & wxCB_READONLY ) );
    }

    inline const wxBitmap& GetBitmapNormal() const { return m_bmpNormal; }
    inline const wxBitmap& GetBitmapPressed() const { return m_bmpPressed; }
    inline const wxBitmap& GetBitmapHover() const { return m_bmpHover; }
    inline const wxBitmap& GetBitmapDisabled() const { return m_bmpDisabled; }
    inline wxUint32 GetInternalFlags() const { return m_iFlags; }
    inline bool IsCreated() const { return m_iFlags & wxPGCC_IFLAG_CREATED ? true : false; }
    virtual bool OnDrawItem( wxDC& dc, const wxRect& rect, int item, int flags ) const;
    virtual wxCoord OnMeasureItem( size_t item ) const;
    virtual wxCoord OnMeasureItemWidth( size_t item ) const;
    inline bool ConsumingTextCtrlFocusEvent() {
      if( m_skipTextCtrlFocusEvents == 0 ) {
        return true;
      }
      m_skipTextCtrlFocusEvents--;
      return false;
    }

  protected:
    virtual void OnResize() = 0;
    virtual wxCoord GetNativeTextIndent() const;
    virtual void OnThemeChange();
    void CreateTextCtrl( int extraStyle, const wxValidator& validator );
    void InstallInputHandlers();

    enum {
      Button_PaintBackground = 0x0001,
      Button_BitmapOnly = 0x0002
    };

    void DrawButton( wxDC& dc, const wxRect& rect, int flags = Button_PaintBackground );
    bool HandleButtonMouseEvent( wxMouseEvent& event, int flags );
    bool PreprocessMouseEvent( wxMouseEvent& event, int flags );
    void HandleNormalMouseEvent( wxMouseEvent& event );
    void CreatePopup();
    void OnPopupDismiss();
    virtual void DoMoveWindow( int x, int y, int width, int height );
    virtual wxSize DoGetBestSize() const;
    void CalculateAreas( int btnWidth = 0 );
    virtual void PositionTextCtrl( int textCtrlXAdjust, int textCtrlYAdjust );
    void OnSizeEvent( wxSizeEvent& event );
    void OnFocusEvent( wxFocusEvent& event );
    void OnKeyEvent( wxKeyEvent& event );
    void OnTextCtrlEvent( wxCommandEvent& event );
    void OnSysColourChanged( wxSysColourChangedEvent& event );
    void Customize( wxUint32 flags ) { m_iFlags |= flags; }
    void RecalcAndRefresh();
    wxString m_valueString;
    wxTextCtrl* m_text;
    wxWindow* m_btn;
    wxWindow* m_winPopup;
    wxWindow* m_popup;
    wxPGComboPopup* m_popupInterface;
    wxEvtHandler* m_textEvtHandler;
    wxEvtHandler* m_toplevEvtHandler;
    wxEvtHandler* m_popupExtraHandler;
    wxLongLong m_timeCanAcceptClick;
    wxCoord m_extLeft;
    wxCoord m_extRight;
    wxCoord m_widthMinPopup;
    wxCoord m_heightPopup;
    wxCoord m_widthCustomPaint;
    wxCoord m_absIndent;
    wxCoord m_widthCustomBorder;
    wxRect m_tcArea;
    wxRect m_btnArea;
    int m_btnState;
    int m_btnWid;
    int m_btnHei;
    int m_btnSide;
    int m_btnSpacingX;
    int m_btnWidDefault;
    wxBitmap                m_bmpNormal;
    wxBitmap m_bmpPressed;
    wxBitmap m_bmpHover;
    wxBitmap m_bmpDisabled;
    wxSize m_btnSize;
    wxUint32 m_iFlags;
    bool m_blankButtonBg;
    bool m_isPopupShown;
    unsigned char m_fakePopupUsage;
    wxByte m_skipTextCtrlFocusEvents;

  private:
    void Init();
    DECLARE_EVENT_TABLE()
    DECLARE_ABSTRACT_CLASS( wxPGComboControlBase )
};

class WXDLLEXPORT_PGODC wxPGGenericComboControl : public wxPGComboControlBase {
  public:
    wxPGGenericComboControl() : wxPGComboControlBase() { Init(); }
    wxPGGenericComboControl( wxWindow *parent,
                             wxWindowID id = wxID_ANY,
                             const wxString& value = wxEmptyString,
                             const wxPoint& pos = wxDefaultPosition,
                             const wxSize& size = wxDefaultSize,
                             long style = 0,
                             const wxValidator& validator = wxDefaultValidator,
                             const wxString& name = wxODComboBoxNameStr )
      : wxPGComboControlBase() {
      Init();
      ( void )Create( parent, id, value, pos, size, style, validator, name );
    }

    bool Create( wxWindow *parent,
                 wxWindowID id = wxID_ANY,
                 const wxString& value = wxEmptyString,
                 const wxPoint& pos = wxDefaultPosition,
                 const wxSize& size = wxDefaultSize,
                 long style = 0,
                 const wxValidator& validator = wxDefaultValidator,
                 const wxString& name = wxODComboBoxNameStr );

    virtual ~wxPGGenericComboControl();
    static int GetFeatures() { return wxPGComboControlFeatures::All; }
  protected:
    virtual void OnResize();
    void OnPaintEvent( wxPaintEvent& event );
    void OnMouseEvent( wxMouseEvent& event );

  private:
    void Init();
    DECLARE_EVENT_TABLE()
    DECLARE_DYNAMIC_CLASS( wxPGGenericComboControl )
};

class WXDLLEXPORT_PGODC wxPGComboControl : public wxPGGenericComboControl {
  public:
    wxPGComboControl() : wxPGGenericComboControl() {}
    wxPGComboControl( wxWindow *parent,
                      wxWindowID id = wxID_ANY,
                      const wxString& value = wxEmptyString,
                      const wxPoint& pos = wxDefaultPosition,
                      const wxSize& size = wxDefaultSize,
                      long style = 0,
                      const wxValidator& validator = wxDefaultValidator,
                      const wxString& name = wxODComboBoxNameStr )
      : wxPGGenericComboControl() {
      ( void )Create( parent, id, value, pos, size, style, validator, name );
    }
    bool Create( wxWindow *parent,
                 wxWindowID id = wxID_ANY,
                 const wxString& value = wxEmptyString,
                 const wxPoint& pos = wxDefaultPosition,
                 const wxSize& size = wxDefaultSize,
                 long style = 0,
                 const wxValidator& validator = wxDefaultValidator,
                 const wxString& name = wxODComboBoxNameStr ) {
      return wxPGGenericComboControl::Create( parent, id, value, pos, size, style, validator, name );
    }

    virtual ~wxPGComboControl() {}

  protected:

  private:
    DECLARE_DYNAMIC_CLASS( wxPGComboControl )
};

enum {
  wxPGCP_IFLAG_CREATED = 0x0001,
};

class WXDLLEXPORT_PGODC wxPGComboPopup {
    friend class wxPGComboControlBase;
  public:
    wxPGComboPopup( wxPGComboControl *combo ) {
      m_combo = combo;
      m_iFlags = 0;
    }
    virtual ~wxPGComboPopup();
    virtual bool Create( wxWindow* parent ) = 0;
    virtual wxWindow *GetControl() = 0;
    virtual void OnPopup();
    virtual void OnDismiss();
    virtual void SetStringValue( const wxString& value );
    virtual wxString GetStringValue() const = 0;
    virtual void PaintComboControl( wxDC& dc, const wxRect& rect );
    virtual void OnComboKeyEvent( wxKeyEvent& event );
    virtual void OnComboDoubleClick();
    virtual wxSize GetAdjustedSize( int minWidth, int prefHeight, int maxHeight );
    virtual bool LazyCreate();
    void Dismiss();
    inline bool IsCreated() const {
      return ( m_iFlags & wxPGCP_IFLAG_CREATED ) ? true : false;
    }
  protected:
    wxPGComboControl* m_combo;
    wxUint32 m_iFlags;
};

enum {
  wxODCB_STD_CONTROL_PAINT = 0x0400
};

enum {
  wxPGCC_PAINTING_CONTROL = 0x0001,
  wxPGCC_PAINTING_SELECTED = 0x0002
};

#include "wx/vlbox.h"

class wxPGVListBoxComboPopup : public wxVListBox, public wxPGComboPopup {
    friend class wxPGOwnerDrawnComboBox;
  public:
    wxPGVListBoxComboPopup( wxPGComboControl* combo );
    virtual ~wxPGVListBoxComboPopup();
    virtual bool Create( wxWindow* parent );
    virtual wxWindow *GetControl() { return this; }
    virtual void SetStringValue( const wxString& value );
    virtual wxString GetStringValue() const;
    virtual void OnPopup();
    virtual wxSize GetAdjustedSize( int minWidth, int prefHeight, int maxHeight );
    virtual void PaintComboControl( wxDC& dc, const wxRect& rect );
    virtual void OnComboKeyEvent( wxKeyEvent& event );
    virtual void OnComboDoubleClick();
    virtual bool LazyCreate();
    void SetSelection( int item );
    void Insert( const wxString& item, int pos );
    int Append( const wxString& item );
    void Clear();
    void Delete( wxODCIndex item );
    void SetItemClientData( wxODCIndex n, void* clientData, wxClientDataType clientDataItemsType );
    void *GetItemClientData( wxODCIndex n ) const;
    void SetString( int item, const wxString& str );
    wxString GetString( int item ) const;
    wxODCCount GetCount() const;
    int FindString( const wxString& s ) const;
    int GetSelection() const;
    void Populate( int n, const wxString choices[] );
    void ClearClientDatas();
    inline int GetItemAtPosition( const wxPoint& pos ) { return HitTest( pos ); }
    inline wxCoord GetTotalHeight() const { return EstimateTotalHeight(); }
    inline wxCoord GetLineHeight( int n ) const { return OnMeasureItem( n ); }
  protected:
    virtual wxCoord OnGetRowHeight( size_t n ) const { return OnMeasureItem( n ); }
    bool HandleKey( int keycode, bool saturate );
    void SendComboBoxEvent( int selection );
    void DismissWithEvent();
    void CheckWidth( int pos );
    virtual void OnDrawItem( wxDC& dc, const wxRect& rect, size_t n ) const;
    virtual wxCoord OnMeasureItem( size_t n ) const;
    void OnDrawBackground( wxDC& dc, const wxRect& rect, size_t n ) const;
    void OnMouseMove( wxMouseEvent& event );
    void OnMouseWheel( wxMouseEvent& event );
    void OnKey( wxKeyEvent& event );
    void OnLeftClick( wxMouseEvent& event );
    void OnMouseCaptureLost( wxMouseCaptureLostEvent& event );
    wxArrayString m_strings;
    wxArrayPtrVoid m_clientDatas;
    wxArrayInt m_widths;
    wxString m_stringValue;
    wxFont m_font;
    int m_value;
    int m_itemHover;
    int m_widestWidth;
    int m_avgCharWidth;
    int m_baseImageWidth;
    int m_itemHeight;
    wxClientDataType m_clientDataItemsType;
  private:
    bool m_clicked;
    DECLARE_EVENT_TABLE()
};

class WXDLLEXPORT_PGODC wxPGOwnerDrawnComboBox : public wxPGComboControl, public wxItemContainer {
    friend class wxPGComboPopupWindow;
    friend class wxPGComboControlBase;
  public:
    wxPGOwnerDrawnComboBox() : wxPGComboControl() { Init(); }
    wxPGOwnerDrawnComboBox( wxWindow *parent, wxWindowID id, const wxString& value, const wxPoint& pos,
                            const wxSize& size, int n, const wxString choices[], long style = 0,
                            const wxValidator& validator = wxDefaultValidator,
                            const wxString& name = wxODComboBoxNameStr )
      : wxPGComboControl() {
      Init();
      ( void )Create( parent, id, value, pos, size, n, choices,
                      style, validator, name );
    }

    bool Create( wxWindow *parent, wxWindowID id, const wxString& value = wxEmptyString,
                 const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
                 long style = 0, const wxValidator& validator = wxDefaultValidator,
                 const wxString& name = wxODComboBoxNameStr );

    wxPGOwnerDrawnComboBox( wxWindow *parent, wxWindowID id, const wxString& value, const wxPoint& pos,
                            const wxSize& size, const wxArrayString& choices, long style = 0,
                            const wxValidator& validator = wxDefaultValidator, const wxString& name = wxODComboBoxNameStr );

    bool Create( wxWindow *parent, wxWindowID id, const wxString& value = wxEmptyString, const wxPoint& pos = wxDefaultPosition,
                 const wxSize& size = wxDefaultSize, int n = 0, const wxString choices[] = ( const wxString * ) NULL,
                 long style = 0, const wxValidator& validator = wxDefaultValidator, const wxString& name = wxODComboBoxNameStr );

    bool Create( wxWindow *parent, wxWindowID id, const wxString& value, const wxPoint& pos, const wxSize& size,
                 const wxArrayString& choices, long style = 0, const wxValidator& validator = wxDefaultValidator,
                 const wxString& name = wxODComboBoxNameStr );

    virtual ~wxPGOwnerDrawnComboBox();
    virtual void Clear();
    virtual void Delete( wxODCIndex n );
    virtual wxODCCount GetCount() const;
    virtual wxString GetString( wxODCIndex n ) const;
    virtual void SetString( wxODCIndex n, const wxString& s );
    virtual int FindString( const wxString& s ) const;
    virtual void Select( int n );
    virtual int GetSelection() const;
    void SetSelection( int n ) { Select( n ); }
    wxCONTROL_ITEMCONTAINER_CLIENTDATAOBJECT_RECAST
  protected:
    void ClearClientDatas();
    virtual int DoAppend( const wxString& item );
    virtual int DoInsert( const wxString& item, wxODCIndex pos );
    virtual void DoSetItemClientData( wxODCIndex n, void* clientData );
    virtual void* DoGetItemClientData( wxODCIndex n ) const;
    virtual void DoSetItemClientObject( wxODCIndex n, wxClientData* clientData );
    virtual wxClientData* DoGetItemClientObject( wxODCIndex n ) const;
    wxPGVListBoxComboPopup* m_popupInterface;
  private:
    void Init();
    DECLARE_EVENT_TABLE()
    DECLARE_DYNAMIC_CLASS( wxPGOwnerDrawnComboBox )
};

#endif
#endif
